﻿#include <windows.h>
#include <QCoreApplication>

#include "qnativewindowfilter.h"
#include "qnativewindowfilter_p.h"
#include "qnativewindowhelper_p.h"

/*
    将本对象作为全局消息过滤器安装到QCoreApplication上。

    将window与helper进行关联，并将系统发送到window上的消息
    分发给helper进行处理。
*/
void QNativeWindowFilter::deliver(QWindow *window, QNativeWindowHelper *helper)
{
    Q_CHECK_PTR(window);

    if (!QNativeWindowFilterPrivate::instance) {
        QCoreApplication *appc = QCoreApplication::instance();
        if (appc) {
            auto filter = new QNativeWindowFilter();
            QNativeWindowFilterPrivate::instance.reset(filter);
            appc->installNativeEventFilter(filter);
        }
    }

    if (helper) {
        WId newId = window->winId();
        WId oldId = QNativeWindowFilterPrivate::windows.value(helper);
        if (newId != oldId) {
            QNativeWindowFilterPrivate::helpers.insert(newId, helper);
            QNativeWindowFilterPrivate::helpers.remove(oldId);
            QNativeWindowFilterPrivate::windows.insert(helper, newId);

            QNativeWindowFilterPrivate::winIds.insert(window, newId);
        }
    } else {
        WId oldId = QNativeWindowFilterPrivate::winIds.take(window);
        QNativeWindowHelper *helper = QNativeWindowFilterPrivate::helpers.take(oldId);
        QNativeWindowFilterPrivate::windows.remove(helper);
    }
}

/*
    如果Qt窗口通过deliver与某个QNativeWindowHelper进行了绑定，则本函数会将
    发送到该Qt窗口上的系统消息分发给对应的QNativeWindowHelper进行处理。
*/
bool QNativeWindowFilter::nativeEventFilter(const QByteArray &eventType,
                                           void *message, long *result)
{
    Q_UNUSED(eventType);

    LPMSG msg = reinterpret_cast<LPMSG>(message);
    if (auto h = QNativeWindowFilterPrivate::helpers.value(reinterpret_cast<WId>(msg->hwnd)))
        return h->nativeEventFilter(msg, result);

    return false;
}

QScopedPointer<QNativeWindowFilter> QNativeWindowFilterPrivate::instance;
QHash<QNativeWindowHelper *, WId> QNativeWindowFilterPrivate::windows;
QHash<QWindow *, WId> QNativeWindowFilterPrivate::winIds;
QHash<WId, QNativeWindowHelper *> QNativeWindowFilterPrivate::helpers;
